﻿using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using ZTool.Domain;
using ZTool.Domain.DO;
using ZTool.Model.DTO;

namespace ZTool.Model
{
    class RegistryCenterService
    {
        private HttpListener httpListener;
        public delegate void HandleRequestsCompletedEventHandler(object sender, EventArgs e);
        public event HandleRequestsCompletedEventHandler HandleRequestsCompleted;
        public RegistryCenterService()
        {
            init();
        }

        private void init()
        {
            // Start the HTTP listener
            httpListener = new HttpListener();
            httpListener.Prefixes.Add("http://localhost:8888/");
            httpListener.Start();

            // Start a background task to handle incoming requests
            Task.Run(HandleRequests);
        }

        private async Task DiscoverServices()
        {
            try
            {
                using (HttpClient httpClient = new HttpClient())
                {
                    string url = "http://localhost:8888/services";
                    string response = await httpClient.GetStringAsync(url);

                    // Process the response, which contains the list of registered services
                    Console.WriteLine("Registered services:");
                    Console.WriteLine(response);
                }
            }
            catch (Exception ex)
            {
                // Handle any exceptions that may occur during the discovery process
                Console.WriteLine("Error discovering services: " + ex.Message);
            }
        }
        private async Task HandleRequests()
        {
            while (true)
            {
                // Wait for an incoming request
                HttpListenerContext context = await httpListener.GetContextAsync();

                ResponseDTO responseData = new ResponseDTO
                {
                    Code = 503,
                    Message = "Unknown error",
                    Data = null
                };

                // Handle the request
                string requestUrl = context.Request.Url.LocalPath.Trim('/');
                if (context.Request.HttpMethod == "POST" && requestUrl == "register")
                {
                    // Read the POST data
                    string postData;
                    using (StreamReader reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
                    {
                        postData = reader.ReadToEnd();
                    }

                    // Deserialize the JSON data
                    dynamic jsonData = JsonConvert.DeserializeObject(postData);
                    string serviceName = jsonData.name;
                    string b64Title = jsonData.title;
                    string title = Base64Util.Decode(b64Title);
                    string address = jsonData.address;
                    int port = jsonData.port;
                    int model = jsonData.model;

                    if (!string.IsNullOrEmpty(serviceName) && !string.IsNullOrEmpty(address) && port != 0)
                    {
                        var now = new TimeDate(DateTime.Now);

                        var server = DomainFactory.Instance.CreateServer(serviceName, title, now, 
                            Address.of(address), Port.of(port), ServerModel.of(model));

                        Console.WriteLine($"Service '{serviceName}' registered.");

                        responseData = new ResponseDTO
                        {
                            Code = 200,
                            Message = $"Service {server.GetName()} registered",
                            Data = null
                        };

                        var arg = new RegistryEventArg();
                        arg.Title = title;
                        arg.Name = serviceName;

                        OnHandleRequestsCompleted(arg);
                    }
                }
                else if (context.Request.HttpMethod == "POST" && requestUrl.StartsWith("heartbeat/"))
                {
                    // Handle service heartbeat
                    // Extract the service name from the URL
                    string serviceName = requestUrl.Substring("heartbeat/".Length);

                    if (DomainFactory.Instance.ValidateServer(serviceName))
                    {
                        DomainFactory.Instance.HeartBeat(serviceName);
                        Console.WriteLine($"Heartbeat received for service '{serviceName}'.");

                        responseData = new ResponseDTO
                        {
                            Code = 200,
                            Message = "Heartbeat received",
                            Data = null
                        };
                    }
                }

                if(null != responseData)
                {
                    // Serialize the response data to JSON
                    string responseJson = JsonConvert.SerializeObject(responseData);

                    // Send the response
                    byte[] responseBytes = Encoding.UTF8.GetBytes(responseJson);
                    context.Response.ContentType = "application/json";
                    context.Response.ContentLength64 = responseBytes.Length;
                    context.Response.OutputStream.Write(responseBytes, 0, responseBytes.Length);
                    context.Response.Close();
                }
            }
        }

        protected virtual void OnHandleRequestsCompleted(RegistryEventArg arg)
        {
            HandleRequestsCompleted?.Invoke(this, arg);
        }
        public async Task<ResponseDTO> Send(string serverName, string data)
        {
            var server = DomainFactory.Instance.GetServer(serverName);
            if(null == server)
            {
                throw new ArgumentException($"unknown server {serverName}");
            }

            JsonPostSender sender = new JsonPostSender();
            string url = $"http://{server.GetAddress()}:{server.GetPort()}";
            var inputDTO = new InputDTO(server.GetName(), data);

            return await sender.SendJsonData(url, inputDTO);
        }
    }
}
